using System;
using System.Collections.Generic;
using System.Text;
using System.IO.Ports;
using System.Threading;

using log4net;


namespace SerialPortIO
{
    public class PortHandler
    {
        static public readonly ILog FileLogger = LogManager.GetLogger("FileLog");
        
        private bool isRunning;
        private SerialPort serialPort;
        private StringBuilder readBuffer;

        private bool startWriting = false;

        Thread readThread;
        Thread writeThread1;
        Thread writeThread2;

        public PortHandler(SerialPort sp)
        {
            serialPort = sp;
            init();
        }
        
        public PortHandler(string portName)
        {
            serialPort = new SerialPort(portName);
            init();
        }

        private void init()
        {
            serialPort.ReadTimeout = 50;
            serialPort.WriteTimeout = 500;

            readBuffer = new StringBuilder();
        }

        public void StartReading(string startStr, IDataHandler dHandler)
        {
            if (isRunning)
            {
                return;
            }
            readThread = new Thread(read);
            readBuffer.Length = 0;
            if (!serialPort.IsOpen)
            {
                serialPort.Open();
            }
            if (startStr != null && startStr.Length > 0)
            {
                serialPort.WriteLine(startStr);
            }
            isRunning = true;
            readThread.Start(dHandler);
        }

        public void read(object dataHandler)
        {
            string str = null;
            while (isRunning)
            {
                try
                {
                    str = serialPort.ReadLine();
                    readBuffer.AppendLine(str);
                    IDataHandler dh = dataHandler as IDataHandler;
                    if (dh != null)
                    {
                        dh.HandleData(str);
                    }
                }
                catch (TimeoutException)
                {
                }
            }
        }

        // to simulate writing to the port
        public void StartWriting(bool forPressure)
        {
            startWriting = false;
            if (isRunning)
            {
                return;
            }
            if (!serialPort.IsOpen)
            {
                serialPort.Open();
            }
            isRunning = true;
            if (forPressure)
            {
                writeThread1 = new Thread(write3);
                writeThread1.Start();
            }
            else
            {
                writeThread1 = new Thread(write1);
                writeThread2 = new Thread(write2);
                writeThread1.Start();
                writeThread2.Start();
            }
        }

        public void write1()
        {
            string[] etco2 = new string[] { "035", "032", "034", "035", "036", "040" };
            string[] breath = new string[] { "016", "015", "014", "013", "015", "010" };
            string[] spo2 = new string[] { "097", "096", "094", "095", "097", "092" };
            string[] pulse = new string[] { "072", "074", "072", "073", "075", "070" };
            
            string str = "";
            
            Random r1 = new Random();

            while (isRunning)
            {
                try
                {
                    LogError("Before serialPort.ReadLine()"); 
                    str = serialPort.ReadLine();
                    LogError("After serialPort.ReadLine() *" + str + "*");
                }
                catch (TimeoutException)
                {
                    str = "";
                }
                if (str == "5")
                {
                    LogError("str == 5");
                    startWriting = true;
                    serialPort.WriteLine(str);
                    LogError("After serialPort.WriteLine(5)");
                }
                else if (str == "x")
                {
                    LogError("str == x");
                    startWriting = false;
                    serialPort.WriteLine(str);
                    LogError("After serialPort.WriteLine(x)");
                }
                if (startWriting)
                {
                    
                    str = "-E" + etco2[r1.Next(4)] + "R" + breath[r1.Next(4)] +
                          "I88Y00S" + spo2[r1.Next(4)] + "P" + pulse[r1.Next(4)] + "Z00";
                    //  str = "-E033R013I00Y00S078P084Z00";
                    LogError("Before serialPort.WriteLine(str)");
                    serialPort.WriteLine(str);
                    LogError("After serialPort.WriteLine(str)");
                    Thread.Sleep(1000);
                }
            }
        }

        public void write2()
        {
            int cnt = 0;
            string[] pleVals = new string[] { "09", "09", "09", "09", "08", "09", "10", "12", "13", "13", "14", "15", "15", "15", "15", "16", "18", "33", "48", "63", "63", "73", "68", "60", "52", "52", "40", "35", "29", "24", "21", "21", "17", "16", "16", "16", "16", "14", "12", "11", "10", "10" };
            string[] capVals = new string[] { "09", "12", "15", "19", "22", "25", "28", "30", "34", "37", "40", "42", "44", "47", "50", "52", "54", "56", "57", "57", "55", "53", "50", "47", "45", "42", "39", "35", "32", "30", "27", "24", "21", "19", "17", "14", "13", "12", "11", "10", "09", "08" };
            
            string str = "";
            while (isRunning)
            {
                try
                {
                    if (startWriting)
                    {
                        if (cnt == capVals.Length)
                        {
                            cnt = 0;
                        }
                        LogError("Before serialPort.WriteLine(c+...)");
                        serialPort.WriteLine("c" + capVals[cnt] + "p" + pleVals[cnt]);
                        LogError("After serialPort.WriteLine(c+...)");
                        cnt++;
                    }
                    
                    Thread.Sleep(20);
                }
                catch (TimeoutException)
                {
                }
            }
        }

        public void write3()
        {
            int cnt = 0;
            string[] pressure = new string[] { "DM1:Torr:-3.21E+04:T00", "DM2:MBAR:0.98E-01:T00", "DM1:Pa:2.88E+04:T00", "DM1:Micron:0.07E-03:T00", "DM1:Pa:4.33E+04:T00" };
            string str = "";
            while (isRunning)
            {
                try
                {
                    if (cnt == pressure.Length)
                    {
                        cnt = 0;
                    }
                    serialPort.WriteLine(pressure[cnt]);
                    //serialPort.WriteLine("DM1:mbar  : 8.93 E+02:T00");
                    cnt++;
                    Thread.Sleep(3000);
                }
                catch (TimeoutException)
                {
                }
            }
        }

        public void Stop()
        {
            isRunning = false;
            if (readThread != null)
            {
                readThread.Join();
            }
            if (writeThread1 != null)
            {
                writeThread1.Join();
            }
            if (writeThread2 != null)
            {
                writeThread2.Join();
            }
            serialPort.Close();
        }

        public string ReadBuffer
        {
            get { return readBuffer.ToString(); }
        }

        public string PortName
        {
            get { return serialPort.PortName; }
            set { serialPort.PortName = value; }
        }

        public int BaudRate
        {
            get { return serialPort.BaudRate; }
            set { serialPort.BaudRate = value; }
        }

        public Parity Parity
        {
            get { return serialPort.Parity; }
            set { serialPort.Parity = value; }
        }

        public int DataBits
        {
            get { return serialPort.DataBits; }
            set { serialPort.DataBits = value; }
        }

        public StopBits StopBits
        {
            get { return serialPort.StopBits; }
            set { serialPort.StopBits = value; }
        }

        public Handshake Handshake
        {
            get { return serialPort.Handshake; }
            set { serialPort.Handshake = value; }
        }

        #region LOGGER
        public static void LogInfo(object msg)
        {
            FileLogger.Info(msg);
        }
        public static void LogDebug(object msg)
        {
            FileLogger.Debug(msg);
        }
        public static void LogWarning(object msg)
        {
            FileLogger.Warn(msg);
        }
        public static void LogError(object msg)
        {
            FileLogger.Error(msg);
        }
        public static void LogFatalError(object msg)
        {
            FileLogger.Fatal(msg);
        }


        #endregion
    }
}
